package com.fiberhome.app.network.upload;


import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;

/**
 * Created by Deed on 2018/1/30.
 */

public class UploadManager {
    /**
     *
     */
    private OkHttpClient okHttpClient;

    private static final AtomicReference<UploadManager> INSTANCE = new AtomicReference<>();


    /**
     * get an instance
     *
     * @return DownloadManager
     */
    public static UploadManager getInstance() {
        for (; ; ) {
            UploadManager current = INSTANCE.get();
            if (current != null) {
                return current;
            }
            current = new UploadManager();
            if (INSTANCE.compareAndSet(null, current)) {
                return current;
            }
        }
    }

    private UploadManager() {
        okHttpClient = new OkHttpClient.Builder().build();
    }

    /**
     * @param ub
     * @param uploadListener
     */
    public void upload(String url, final UploadBean ub, final UploadListener uploadListener) {

        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        File file = new File(ub.getFilePath());
        RequestBodyProxy prb = new RequestBodyProxy(
                RequestBody.create(MediaType.parse(ub.getMediaType()), file),
                new ProgressRequestListener() {
                    @Override
                    public void onRequestProgress(long bytesWritten, long contentLength, boolean done) {
                        if (done) {
                            uploadListener.onComplete(ub);
                        } else {
                            uploadListener.onUpdate(ub, bytesWritten, contentLength);
                        }
                    }
                });

        builder.addFormDataPart(ub.getKey(), file.getName(),
                prb);
        Request request = new Request.Builder()
                .url(url)//地址
                .post(builder.build())//添加请求体
                .build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                uploadListener.onFail(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    uploadListener.onFinish();
                } else {
                    uploadListener.onFail(new Throwable(response.message()));
                }
            }
        });
    }

    /**
     * @param url String
     * @param ubList
     * @param multiUploadListener
     */
    public void upload(String url, List<UploadBean> ubList, final MultiUploadListener multiUploadListener) {
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        final List<UploadBean> finishBeans = new ArrayList<>();
        for (final UploadBean ub : ubList) {
            File file = new File(ub.getFilePath());
            RequestBodyProxy prb = new RequestBodyProxy(
                    RequestBody.create(MediaType.parse(ub.getMediaType()), file),
                    new ProgressRequestListener() {
                        @Override
                        public void onRequestProgress(long bytesWritten, long contentLength, boolean done) {
                            if (done) {
                                multiUploadListener.onComplete(ub);
                                finishBeans.add(ub);
                            } else {
                                multiUploadListener.onUpdate(ub, bytesWritten, contentLength);
                            }
                        }
                    });

            builder.addFormDataPart(ub.getKey(), file.getName(),
                    prb);
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                multiUploadListener.onFail(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    multiUploadListener.onFinish(finishBeans);
                } else {
                    multiUploadListener.onFail(new Throwable(response.message()));
                }
            }
        });

    }

    /**
     *
     */
    static class RequestBodyProxy extends RequestBody {


        private RequestBody requestBody;
        private ProgressRequestListener progressListener;
        private BufferedSink bufferedSink;

        /**
         *
         * @param requestBody RequestBody
         * @param progressListener ProgressRequestListener
         */
        public RequestBodyProxy(RequestBody requestBody, ProgressRequestListener progressListener) {
            this.requestBody = requestBody;
            this.progressListener = progressListener;
        }

        @Override
        public MediaType contentType() {
            return requestBody.contentType();
        }

        /**
         * @return contentLength
         * @throws IOException exception
         */
        @Override
        public long contentLength() throws IOException {
            return requestBody.contentLength();
        }

        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            if (bufferedSink == null) {
                bufferedSink = Okio.buffer(sink(sink));
            }
            requestBody.writeTo(bufferedSink);
            bufferedSink.flush();
        }

        /**
         * @param sink Sink
         * @return Sink
         */
        private Sink sink(Sink sink) {
            return new ForwardingSink(sink) {
                long bytesWritten = 0L;
                long contentLength = 0L;

                @Override
                public void write(Buffer source, long byteCount) throws IOException {
                    super.write(source, byteCount);
                    if (contentLength == 0) {
                        contentLength = contentLength();
                    }
                    bytesWritten += byteCount;
                    if (progressListener != null) {
                        progressListener.onRequestProgress(bytesWritten, contentLength,
                                bytesWritten == contentLength);
                    }
                }
            };
        }
    }

    /**
     *
     */
    interface ProgressRequestListener {
        /**
         * @param bytesWritten  long
         * @param contentLength long
         * @param done          boolean
         */
        void onRequestProgress(long bytesWritten, long contentLength, boolean done);
    }
}
